package com.xiaoyu.im.datamodel;

import android.text.TextUtils;

import androidx.annotation.NonNull;

import com.xiaoyu.im.client.proxy.nim.AntiSpamResult;
import com.xiaoyu.base.entity.MessageEntity;
import com.xiaoyu.base.data.UserData;
import com.xiaoyu.im.ChatToken;
import com.xiaoyu.im.datamodel.vendors.VendorConversationUnique;
import com.xiaoyu.im.provider.MessageStatusProcessor;
import com.xiaoyu.base.remoteconfig.RemoteConfigClient;
import com.xiaoyu.base.utils.ListUtil;

import java.util.UUID;

import in.srain.cube.request.JsonData;
import in.srain.cube.util.time.TimeData;
import in.srain.cube.util.StringUtil;

import static com.xiaoyu.im.datamodel.MessagePayload.KEY_NEW_TIP;

public class AppMessage {

    public final String id;
    @MessageIdType.MessageIdTypeStringDef
    public final String idType;
    public final String vendorCid;
    public final String localId;
    public final long time;
    public long displayTime;
    public final String senderUid;
    public final ChatToken chatToken;
    public final MessagePayload payload;
    public final int syncPoint;
    public final boolean invisible;
    public final boolean invisibleLastContent;
    @MessageStatus.MessageStatusDef
    private int mStatus;
    @ReadReceipt.ReadReceiptDef
    private int mReadReceipt;
    private JsonData attributes;

    public static AppMessage create(ChatToken chatToken, MessagePayload payload) {
        return new AppMessage(chatToken, payload);
    }

    public static AppMessage fromEntity(MessageEntity entity) {
        return new AppMessage(entity);
    }

    private AppMessage(ChatToken chatToken, MessagePayload payload) {
        final String uuid = UUID.randomUUID().toString();
        final long time = TimeData.getInstance().getServerTime().getTime();
        final String uid = UserData.getInstance().getUid();
        this.id = uuid;
        this.idType = MessageIdType.STR_LOCAL;
        this.vendorCid = "";
        this.localId = uuid;
        this.time = time;
        this.displayTime = time;
        this.senderUid = StringUtil.blankIfNull(uid);
        this.chatToken = chatToken;
        this.payload = payload;
        this.syncPoint = 0;
        this.invisible = false;
        this.invisibleLastContent = false;
        this.mReadReceipt = ReadReceipt.UNREAD;
        this.mStatus = MessageStatus.INIT;
        this.attributes = JsonData.newMap();
    }

    private AppMessage(MessageEntity entity) {
        this.id = entity.getId();
        this.idType = MessageIdType.intToStr(entity.getIdType());
        this.vendorCid = entity.getCid();
        this.localId = entity.getLocalId();
        this.time = entity.getTime();
        this.displayTime = entity.getDisplayTime();
        this.senderUid = StringUtil.blankIfNull(entity.getSenderUid());
        this.chatToken = ChatToken.createOrEmpty(entity.getChatId(), entity.getTargetUid());
        this.payload = MessagePayload.fromEntity(entity);
        this.syncPoint = entity.getSyncPoint();
        this.invisible = entity.isInvisible();
        this.invisibleLastContent = entity.isInvisibleLastContent();
        this.mReadReceipt = entity.getReadReceipt();
        this.mStatus = entity.getStatus();
        this.attributes = TextUtils.isEmpty(entity.getAttributes()) ? JsonData.newMap() : JsonData.create(entity.getAttributes());
    }

    public MessageEntity toEntity() {
        final MessageEntity entity = new MessageEntity();
        entity.setId(id);
        entity.setIdType(MessageIdType.strToInt(idType));
        entity.setCid(vendorCid);
        entity.setLocalId(localId);
        entity.setTime(time);
        entity.setDisplayTime(displayTime);
        entity.setSenderUid(senderUid);
        entity.setChatId(chatToken.getChatId());
        entity.setTargetUid(chatToken.getUid());
        entity.setContent(payload.toString());
        entity.setPayloadVersion(payload.getCurrentVersion());
        entity.setType(payload.getMessageType());
        entity.setMentionAll(payload.isMentionAll());
        if (!ListUtil.isNullOrEmpty(payload.getMentionList())) {
            entity.setMentionListString(JsonData.create(payload.getMentionList()).toString());
        }
        entity.setSyncPoint(syncPoint);
        entity.setInvisible(invisible);
        entity.setInvisibleLastContent(invisibleLastContent);
        entity.setText(payload.getText());
        entity.setReadReceipt(mReadReceipt);
        entity.setStatus(mStatus);
        entity.setAttributes(attributes.toString());
        return entity;
    }

    public long getDisplayTime() {
        return displayTime;
    }

    public void setDisplayTime(long displayTime) {
        this.displayTime = displayTime;
    }

    public int getStatus() {
        return mStatus;
    }

    public void setStatus(@MessageStatus.MessageStatusDef int status) {
        mStatus = status;
    }

    @ReadReceipt.ReadReceiptDef
    public int getReadReceipt() {
        return mReadReceipt;
    }

    public boolean isReadReceipt() {
        return mReadReceipt == ReadReceipt.READ;
    }

    public void setReadReceipt() {
        this.mReadReceipt = ReadReceipt.READ;
    }

    public void readNewTip() {
        this.payload.putAttrs(KEY_NEW_TIP, false);
    }

    public boolean hasNewTip() {
        JsonData attrs = this.payload.getAttrsCopy();
        return !attrs.has(KEY_NEW_TIP) || attrs.optBoolean(KEY_NEW_TIP);
    }

    public void setFileRemoteUrl(String url) {
        payload.setUrl(url);
    }

    public void bindVendorUnique(VendorConversationUnique unique) {
        this.attributes.put("vendor_conversation_unique", unique.toJson());
    }

    public JsonData getVendorUniqueJson() {
        return this.attributes.optJson("vendor_conversation_unique");
    }

    public int toDisplayStatus() {
        final int status = mStatus;
        if (status == MessageStatus.SUCCESS) {
            return MessageDisplayStatus.SUCCESS;
        }
        if (!MessageStatus.isFailedStatus(status) && MessageStatusProcessor.getInstance().isSending(id)) {
            return MessageDisplayStatus.SENDING;
        }
        return status == MessageStatus.BLACKED_FAILED ? MessageDisplayStatus.BLACKED_FAIL : MessageDisplayStatus.NORMAL_FAIL;
    }

    // decide whether two object represent the same item on ui
    public boolean isSameItemOnUI(AppMessage o) {
        return equals(o) || (!TextUtils.isEmpty(localId) && TextUtils.equals(localId, o.localId));
    }

    public boolean shouldSetServerForbidden() {
        boolean forbidWhenHit = RemoteConfigClient.getInstance().getBoolean("features.im.forbid_when_hit_server_forbidden", false);
        if (!forbidWhenHit) {
            return false;
        }
        final String antiSpamOperator = payload.getAttrsCopy().optString("anti_spam_operator");
        return TextUtils.equals(antiSpamOperator, AntiSpamResult.OPERATOR_TYPE_SERVER_FORBIDDEN);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        AppMessage message = (AppMessage) o;
        return TextUtils.equals(id, message.id);
    }

    @Override
    public int hashCode() {
        return id.hashCode();
    }

    @NonNull
    @Override
    public String toString() {
        return "AppMessage{" +
                "id='" + id + '\'' +
                ", idType='" + idType + '\'' +
                ", vendorCid='" + vendorCid + '\'' +
                ", localId='" + localId + '\'' +
                ", time=" + time +
                ", displayTime=" + displayTime +
                ", senderUid='" + senderUid + '\'' +
                ", chatToken=" + chatToken +
                ", payload=" + payload +
                ", syncPoint=" + syncPoint +
                ", attributes=" + attributes +
                ", mReadReceipt=" + mReadReceipt +
                ", mStatus=" + mStatus +
                '}';
    }
}
